#include "accelerometer.h"
#include "battery.h"
#include "device.h"
#include "display.h"
#include "flash.h"
#include "iap.h"
#include "iic.h"
#include "power.h"
#include "rtc.h"
#include "usb.h"
#include "version.h"

#define	SIGN_SAV		0x55aa55aa

#define SYSCTRL			((uint)0xE000ED10)
#define DEEP_SLEEP		((uint)0x00000004)

static void clock(uint hclk){
	SystemCoreClockUpdate();
	RCC_HCLKConfig(hclk);
	RCC_APB1PeriphClockCmd(
		RCC_APB1Periph_BKP|
		RCC_APB1Periph_I2C2|
		RCC_APB1Periph_PWR,ENABLE);
	RCC_APB2PeriphClockCmd(
		RCC_APB2Periph_AFIO|
		RCC_APB2Periph_GPIOA|
		RCC_APB2Periph_GPIOB|
		RCC_APB2Periph_GPIOC|
		RCC_APB2Periph_TIM1,ENABLE);
	PWR_BackupAccessCmd(ENABLE);
}
static void nvic(void){
	NVIC_SetVectorTable(NVIC_VectTab_FLASH,version_vect);
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

	NVIC_InitTypeDef n;
	n.NVIC_IRQChannel=EXTI0_IRQn;		// WKUP
	n.NVIC_IRQChannelPreemptionPriority=3;
	n.NVIC_IRQChannelSubPriority=1;
	n.NVIC_IRQChannelCmd=ENABLE;
	NVIC_Init(&n);
	n.NVIC_IRQChannel=EXTI15_10_IRQn;	// GSINT
	n.NVIC_IRQChannelPreemptionPriority=3;
	n.NVIC_IRQChannelSubPriority=1;
	n.NVIC_IRQChannelCmd=ENABLE;
	NVIC_Init(&n);
	n.NVIC_IRQChannel=I2C2_EV_IRQn;		// IIC2
	n.NVIC_IRQChannelPreemptionPriority=0;
	n.NVIC_IRQChannelSubPriority=0;
	n.NVIC_IRQChannelCmd=ENABLE;
	NVIC_Init(&n);
	n.NVIC_IRQChannel=ADC1_2_IRQn;		// ADC
	n.NVIC_IRQChannelPreemptionPriority=3;
	n.NVIC_IRQChannelSubPriority=1;
	n.NVIC_IRQChannelCmd=ENABLE;
	NVIC_Init(&n);

	EXTI_DeInit();
	EXTI_InitTypeDef x;
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,PINSRC_WKUP);
	x.EXTI_Line	  =EXTI_WKUP;
	x.EXTI_Mode	  =EXTI_Mode_Interrupt;
	x.EXTI_Trigger=EXTI_Trigger_Rising;
	x.EXTI_LineCmd=ENABLE;
	EXTI_Init(&x);
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,PINSRC_GSINT);
	x.EXTI_Line	  =EXTI_GSINT;
	x.EXTI_Mode	  =EXTI_Mode_Interrupt;
	x.EXTI_Trigger=EXTI_Trigger_Rising;
	x.EXTI_LineCmd=ENABLE;
	EXTI_Init(&x);
	NVIC_SetPriority(SysTick_IRQn,1);
}
static void gpio(void){
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);   //Use SWD
	GPIO_InitTypeDef g;
	g.GPIO_Speed=GPIO_Speed_50MHz;

	g.GPIO_Pin	=PIN_CHIN;
	g.GPIO_Mode	=GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOA,&g);
	g.GPIO_Pin	=PIN_CHOUT;
	g.GPIO_Mode	=GPIO_Mode_Out_OD;
	GPIO_SetBits(GPIOA,g.GPIO_Pin);
	GPIO_Init(GPIOA,&g);
	g.GPIO_Pin	=PIN_Y0_Y2;
	g.GPIO_Mode	=GPIO_Mode_Out_PP;
	GPIO_ResetBits(GPIOA,g.GPIO_Pin);
	GPIO_Init(GPIOA,&g);
    g.GPIO_Pin	=PIN_WKUP;
    g.GPIO_Mode	=GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA,&g);

    g.GPIO_Pin	=PIN_GSINT;
    g.GPIO_Mode	=GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOB,&g);
	g.GPIO_Pin	=PIN_Y3_Y9;
	g.GPIO_Mode	=GPIO_Mode_Out_PP;
	GPIO_ResetBits(GPIOB,g.GPIO_Pin);
	GPIO_Init(GPIOB,&g);
	g.GPIO_Pin	=PIN_I2C;
	g.GPIO_Mode	=GPIO_Mode_AF_OD;
	GPIO_SetBits(GPIOB,g.GPIO_Pin);
	GPIO_Init(GPIOB,&g);

	g.GPIO_Pin	=PIN_VOLT;
	g.GPIO_Mode	=GPIO_Mode_AIN;
	GPIO_Init(GPIOC,&g);
	g.GPIO_Pin	=PIN_X0_Y9;
	g.GPIO_Mode	=GPIO_Mode_Out_OD;
	GPIO_SetBits(GPIOC,g.GPIO_Pin);
	GPIO_Init(GPIOC,&g);
}
static void restore(void){
	ushort ex=BKP_ReadBackupRegister(BACKUP_EXTRA);
	savRam.timeOfs=BKP_ReadBackupRegister(BACKUP_TMOFSL)+
		(BKP_ReadBackupRegister(BACKUP_TMOFSH)<<16);
	curSteps=BKP_ReadBackupRegister(BACKUP_STEPS)+((ex&1)<<16);
	ex=BKP_ReadBackupRegister(BACKUP_BOOTS);
	BKP_WriteBackupRegister(BACKUP_BOOTS,ex+1);
	if(savRom.signSav==SIGN_SAV)
		savRam.accBase=savRom.accBase;
	else savRam.signSav=SIGN_SAV;
}

//------------------------------------------------------------------------------

void device_checkPower(void){
	meterOn();
	if(powerSignal())
		PWR_EnterSTANDBYMode();		
	meterOff();
}
void device_feedDog(void){
	IWDG_ReloadCounter();
}
void device_init(uint fast){
	clock(fast?RCC_SYSCLK_Div2:RCC_SYSCLK_Div512);
	rtc_init();
	nvic();
	gpio();
	restore();
	*(uint*)SYSCTRL&=~DEEP_SLEEP;
}
void device_speed(uint fast){
	RCC_HCLKConfig(fast?RCC_SYSCLK_Div2:RCC_SYSCLK_Div2);
}
void device_standby(void){
	PWR_EnterSTANDBYMode();
}
uint device_status(void){
	return getStatus();
}
void device_timer(uint seconds){
}
void device_watchdog(uint longPeriod){
	IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
	IWDG_SetPrescaler(IWDG_Prescaler_256);
	IWDG_SetReload(longPeriod?0xfff:0x3ff);
	IWDG_ReloadCounter();
	IWDG_Enable();
}
void device_updateVecTable(void){
	uint* a=0;
	uint* b=(uint*)version_vect;
	uint* c=(uint*)256;
	while(a<c)if(*a++!=*b++){
		flash_begin();
		flash_erasePage(a);
		flash_copy(0,(void*)version_vect,1024);
		flash_end();
		break;
	}
}
